package com.mjk.common.tools.scheduled.single.impl;


import com.mjk.common.core.redis.datatype.RedisUtils;
import com.mjk.common.core.redis.listener.annotation.BeeRedisListener;
import com.mjk.common.core.redis.listener.annotation.RedisKeyEvent;
import com.mjk.common.tools.scheduled.single.SinglePointInterface;
import com.mjk.common.util.ComputerUtils;
import com.mjk.common.util.ThreadUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.ObjectUtils;

import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
/**
 * 基于redis的单点执行 判断
 * @author mjk
 *
 */
public class RedisSingelPointImpl implements SinglePointInterface,ApplicationContextAware{
	@Autowired
	private RedisTemplate redisTemplate;
	
	@Value(value="${server.port:8080}")
	private String nodeName ;
	
	final Map<String,DataSingleListener> listeners = new ConcurrentHashMap<>();
	
	@Override
	public boolean isSingelRun() {
		String value = (String) RedisUtils.get(redisTemplate, ROOT_PATH);
		if(ObjectUtils.isEmpty(value)){
			RedisUtils.set(redisTemplate, ROOT_PATH, nodeName);
			//此处在多节点的情况下可能会存在多个节点修改的问题，所以这里获取redis中保存的值
			value = (String)RedisUtils.get(redisTemplate, ROOT_PATH);
		}
        return nodeName.endsWith(value);
    }

	@BeeRedisListener(evnet= RedisKeyEvent.UPDATE)
	public void redisKeyNotic(String key){
		for(Entry<String,DataSingleListener> entry : listeners.entrySet()){			
			if(key.equals(entry.getKey())){
				entry.getValue().onListener(entry.getKey(), "");				
			}							
		}	
	}
	
	@Override
	public void registerListener(String node, DataSingleListener listener) {
		listeners.put(node, listener);
	}
	
	@Override
	public void setNotic(String node, String value) {
		RedisUtils.setex(redisTemplate, node, value, 1);		
	}
	
	/**
	 * 设置通知，带超时时间
	 */
	@Override
	public void setNotic(String node, String value,long timeOut) {
		if(timeOut>0){
			timeOutExecutor.execute(() -> {
                ThreadUtils.sleep(timeOut);
                setNotic(node, value);
            });
		}else{
			setNotic(node, value);
		}		
	}
	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		nodeName = ComputerUtils.getHostName()+"-"+nodeName;
		RedisUtils.set(redisTemplate, ROOT_PATH, nodeName);
		Runtime.getRuntime().addShutdownHook(
                new Thread(() -> RedisUtils.set(redisTemplate, ROOT_PATH, ""))
		);
	}

}
